
package com.example.videotrim;

import com.example.videotrim.utils.FfmpegTrimmer;
import com.example.videotrim.utils.S3dVideo;
import com.example.videotrim.utils.TrimmerBar;
import com.example.videotrim.utils.TrimmerBar.OnTrimBarListener;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.media.MediaScannerConnection;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.VideoView;

public class VideoTrimmer extends Activity implements OnTouchListener, OnTrimBarListener,
        OnPreparedListener, OnErrorListener, OnCompletionListener {
    private final String TAG = "VideoTrimmer";

    private int mMediaDuration = 0;

    private Uri mVideoUri = null;

    private TextView mTrimStartTimeTextView = null;

    private TextView mTrimEndTimeTextView = null;

    private boolean mWasPlaying = false;

    private VideoView mTrimVideoView = null;

    private TrimmerBar mTrimBar = null;

    private Handler mTickHandler = null;

    private int mTrimBarLeftTime = 0;

    private int mTrimBarRightTime = 0;

    private ImageView mTrimIconImageView = null;

    private ImageView mPauseIconImageView = null;

    private ImageView mS3dIconImageView = null;

    private static final int DIALOG_ID_TRIM_OPTION = 0x1;

    private static final int DIALOG_ID_TRIM_PROGRESS = 0x2;

    private static final int DIALOG_ID_TRIM_ERROR = 0x3;

    private static final int DIALOG_ID_PLAY_ERROR = 0x4;

    private String mMediaFilePath = null;

    private long mMediaId = -1;

    private MediaPlayer mMediaPlayer = null;

    private S3dVideo mS3dVideo = null;

    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        int msec = savedInstanceState.getInt("current_position");
        int tblt = savedInstanceState.getInt("left_trimbar");
        int tbrt = savedInstanceState.getInt("right_trimbar");
        mMediaDuration = savedInstanceState.getInt("media_duration");
        mTrimBar.setMediaDuration(mMediaDuration);
        mTrimBar.setTrimLeftTime(tblt);
        updateTrimBarStartTime(tblt);
        mTrimBar.setTrimRightTime(tbrt);
        updateTrimBarEndTime(tbrt);
        mTrimVideoView.seekTo(msec);
        mTrimBar.updatePlayTick(msec);
    }

    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("left_trimbar", mTrimBarLeftTime);
        outState.putInt("right_trimbar", mTrimBarRightTime);
        outState.putInt("media_duration", mMediaDuration);
        outState.putInt("current_position", mMediaPlayer.getCurrentPosition());
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.video_trimmer);

        Intent intent = getIntent();
        String action = intent.getAction();

        if (action.equals(Intent.ACTION_VIEW)) {
            Uri uri = intent.getData();

            if (uri.getScheme().equals("content")) {
                String[] mediaColumns = {
                        MediaStore.Video.Media._ID, MediaStore.Video.Media.DATA
                };
                Cursor cursor = managedQuery(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                        mediaColumns, "_ID=" + uri.getLastPathSegment(), null, null);
                cursor.moveToFirst();
                mMediaFilePath = cursor.getString(cursor
                        .getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
                mMediaId = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media._ID));
            } else if (uri.getScheme().equals("file")) {
                mMediaFilePath = uri.getPath();
                mMediaId = intent.getLongExtra("mediaId", -1);
            }

            if (mMediaFilePath == null)
                finish();

            mTrimIconImageView = (ImageView) findViewById(R.id.trim_image);
            mTrimIconImageView.setOnTouchListener(this);

            mPauseIconImageView = (ImageView) findViewById(R.id.pause_image);
            mPauseIconImageView.setVisibility(View.INVISIBLE);

            mTrimBar = (TrimmerBar) findViewById(R.id.trimmerBar);
            mTrimBar.setOnTrimBarListener(this);

            mVideoUri = Uri.parse(mMediaFilePath);

            mTrimVideoView = (VideoView) findViewById(R.id.video_view);
            mTrimVideoView.setVideoURI(mVideoUri);
            mTrimVideoView.setOnPreparedListener(this);
            mTrimVideoView.setOnTouchListener(this);
            mTrimVideoView.setOnErrorListener(this);
            mTrimVideoView.setOnCompletionListener(this);

            mTrimEndTimeTextView = (TextView) findViewById(R.id.end_pos_text);
            mTrimStartTimeTextView = (TextView) findViewById(R.id.start_pos_text);

            try {
                mS3dVideo = new S3dVideo(this, mMediaId);
                mS3dVideo.init();
            } catch (Throwable e) {
                e.printStackTrace();
            }

            mS3dIconImageView = (ImageView) findViewById(R.id.s3d_image);
            mS3dIconImageView.setVisibility(View.GONE);
            mS3dIconImageView.setOnTouchListener(this);
        } else {
            finish();
        }
    }

    protected Dialog onCreateDialog(int id) {
        Dialog dialog = null;
        AlertDialog.Builder builder;
        switch (id) {
            case DIALOG_ID_TRIM_OPTION:
                final CharSequence items[] = new CharSequence[2];

                items[0] = getString(R.string.trim_original);
                items[1] = getString(R.string.save_as_new_clip);

                builder = new AlertDialog.Builder(this);
                builder.setTitle(R.string.trim);
                builder.setNegativeButton(R.string.cancel, null);
                builder.setItems(items, new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog, int which) {
                        final boolean overwrite = (which == 0) ? true : false;
                        VideoTrimmer.this.showDialog(DIALOG_ID_TRIM_PROGRESS);

                        new Thread(new Runnable() {
                            MediaScannerConnection msc = null;

                            public void run() {
                                FfmpegTrimmer trimmer = new FfmpegTrimmer(VideoTrimmer.this);
                                final String newFilePath = trimmer.trim(mMediaFilePath,
                                        mTrimBarLeftTime, mTrimBarRightTime, overwrite);

                                if (newFilePath == null) {
                                    VideoTrimmer.this.runOnUiThread(new Runnable() {
                                        public void run() {
                                            VideoTrimmer.this.showDialog(DIALOG_ID_TRIM_ERROR);
                                        }
                                    });
                                } else {
                                    Intent intent = new Intent();
                                    intent.putExtra("mediaId", mMediaId);

                                    if (overwrite) {
                                        setResult(VideoChooser.RESULT_TRIM_OVERWRITE, intent);
                                    } else {
                                        setResult(VideoChooser.RESULT_TRIM_CREATE, intent);
                                    }
                                }
                                msc = new MediaScannerConnection(VideoTrimmer.this,
                                        new MediaScannerConnectionClient() {
                                            public void onScanCompleted(String path, Uri uri) {
                                                msc.disconnect();
                                                VideoTrimmer.this
                                                        .dismissDialog(DIALOG_ID_TRIM_PROGRESS);
                                                VideoTrimmer.this.finish();
                                            }

                                            public void onMediaScannerConnected() {
                                                msc.scanFile(newFilePath, null);
                                            }
                                        });
                                msc.connect();
                            }
                        }).start();
                    }
                });
                dialog = builder.create();
                break;
            case DIALOG_ID_TRIM_PROGRESS:
                dialog = ProgressDialog.show(this, null, getString(R.string.trimming), true, false);
                break;
            case DIALOG_ID_TRIM_ERROR:
                builder = new AlertDialog.Builder(this);
                builder.setMessage(R.string.trim_error).setCancelable(false).setPositiveButton(
                        R.string.ok, null);
                dialog = builder.create();
                break;
            case DIALOG_ID_PLAY_ERROR:
                builder = new AlertDialog.Builder(this);
                builder.setMessage(R.string.video_not_played).setCancelable(false)
                        .setPositiveButton(R.string.ok, null);
                builder.setTitle(R.string.play_error);
                dialog = builder.create();
                break;
            default:
                break;
        }
        return dialog;
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) {
        return super.onKeyDown(keyCode, event);
    }

    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        Log.v(TAG, "onTouch --> v:" + v + ", action:" + action);

        if (v instanceof ImageView && (ImageView) v == mTrimIconImageView) {
            if (action == MotionEvent.ACTION_UP) {
                showDialog(DIALOG_ID_TRIM_OPTION);
            }
            return true;
        }

        if (v instanceof ImageView && (ImageView) v == mS3dIconImageView) {
            if (action == MotionEvent.ACTION_UP) {
                if (mS3dVideo.isS3dVideo()) {
                    if (mS3dVideo.isS3dMode()) {
                        if (mS3dVideo.setS3dDisplay(false))
                            mS3dIconImageView.setImageResource(R.drawable.icon_2d);
                    } else {
                        if (mS3dVideo.setS3dDisplay(true))
                            mS3dIconImageView.setImageResource(R.drawable.icon_3d);
                    }
                    mS3dIconImageView.setVisibility(View.VISIBLE);
                    if (mTrimVideoView.isPlaying() == false) {
                        mPauseIconImageView.setVisibility(View.INVISIBLE);
                        mTrimVideoView.start();
                        startTickEvent();
                    }
                } else {
                    mS3dIconImageView.setVisibility(View.GONE);
                }
            }
            return true;
        }

        if (v instanceof VideoView && (VideoView) v == mTrimVideoView) {
            if (action == MotionEvent.ACTION_DOWN) {
                if (mTrimVideoView.isPlaying() == false) {
                    mPauseIconImageView.setVisibility(View.INVISIBLE);
                    int currentPosition = mTrimVideoView.getCurrentPosition();
                    if (currentPosition == mTrimBarRightTime)
                        mTrimVideoView.seekTo(mTrimBarLeftTime);
                    mTrimVideoView.start();
                    startTickEvent();
                } else {
                    mPauseIconImageView.setVisibility(View.VISIBLE);
                    mTrimVideoView.pause();
                }
            }
            return true;
        }
        return false;
    }

    public boolean onTrimBarChanged(int mode, int msec) {
        Log.v(TAG, "onTrimBarChanged --> mode:" + mode + ", msec:" + msec);
        switch (mode) {
            case OnTrimBarListener.TRIMBAR_ACTION_LEFT_PRESSED:
            case OnTrimBarListener.TRIMBAR_ACTION_RIGHT_PRESSED:
                if (mTrimVideoView.isPlaying() == true) {
                    mWasPlaying = true;
                    mPauseIconImageView.setVisibility(View.VISIBLE);
                    mTrimVideoView.pause();
                } else {
                    mWasPlaying = false;
                }
                break;
            case OnTrimBarListener.TRIMBAR_ACTION_LEFT_MOVED:
                updateTrimBarStartTime(msec);
                // mTrimVideoView.seekTo(msec);
                break;
            case OnTrimBarListener.TRIMBAR_ACTION_RIGHT_MOVED:
                updateTrimBarEndTime(msec);
                // mTrimVideoView.seekTo(msec);
                break;
            case OnTrimBarListener.TRIMBAR_ACTION_LEFT_RELEASED:
                updateTrimBarStartTime(msec);
                mTrimVideoView.seekTo(msec);
                // if(mWasPlaying == true) {
                if (mTrimVideoView.isPlaying() == false) {
                    mPauseIconImageView.setVisibility(View.INVISIBLE);
                    mTrimVideoView.start();
                    startTickEvent();
                }
                break;
            case OnTrimBarListener.TRIMBAR_ACTION_RIGHT_RELEASED:
                updateTrimBarEndTime(msec);
                mTrimVideoView.seekTo(msec);
                // if(mWasPlaying == true) {
                if (mTrimVideoView.isPlaying() == false) {
                    mPauseIconImageView.setVisibility(View.INVISIBLE);
                    mTrimVideoView.start();
                    startTickEvent();
                }
                break;
        }
        return true;
    }

    private void updateTrimBarStartTime(int msec) {
        mTrimBarLeftTime = msec;
        mTrimStartTimeTextView.setText(String.format(getString(R.string.start_) + "%2d:%02d:%02d",
                msec / (60 * 60 * 1000), (msec / (60 * 1000)) % 60, (msec / 1000) % 60));
    }

    private void updateTrimBarEndTime(int msec) {
        mTrimBarRightTime = msec;
        mTrimEndTimeTextView.setText(String.format(getString(R.string.end_) + "%2d:%02d:%02d", msec
                / (60 * 60 * 1000), (msec / (60 * 1000)) % 60, (msec / 1000) % 60));
    }

    public void onPrepared(MediaPlayer mp) {
        if (mMediaDuration == 0) {
            mMediaDuration = mTrimVideoView.getDuration();
            Log.v(TAG, "onPrepared --> duration:" + mMediaDuration);
            mTrimBar.setMediaDuration(mMediaDuration);
            updateTrimBarStartTime(0);
            updateTrimBarEndTime(mMediaDuration);
        }
        mPauseIconImageView.setVisibility(View.INVISIBLE);
        mMediaPlayer = mp;
        mp.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {
            public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
                LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                        ViewGroup.LayoutParams.FILL_PARENT);
                mTrimVideoView.setLayoutParams(lp);
            }
        });
        mS3dVideo.setSurfaceHolder(mTrimVideoView.getHolder());
        mS3dVideo.setMediaPlayer(mp);
        mTrimVideoView.start();
        startTickEvent();
    }

    public boolean onError(MediaPlayer mp, int what, int extra) {
        showDialog(DIALOG_ID_PLAY_ERROR);
        return true;
    }

    public void onCompletion(MediaPlayer mp) {
        mTrimVideoView.seekTo(mTrimBarLeftTime);
        mTrimBar.updatePlayTick(mTrimBarLeftTime);
    }

    private boolean startTickEvent() {
        if (mTickHandler == null)
            mTickHandler = new Handler();

        return mTickHandler.postDelayed(new Runnable() {
            public void run() {
                if (mTrimVideoView.isPlaying()) {
                    int currentPosition = mTrimVideoView.getCurrentPosition();
                    Log.v(TAG, "run --> tick:" + currentPosition);

                    if (0 <= currentPosition && currentPosition <= mTrimBarRightTime) {
                        mTrimBar.updatePlayTick(currentPosition);
                        mTickHandler.postDelayed(this, 200);
                    } else { // (-1 < currentPosition || mTrimBarLeftTime <
                        // currentPosition)
                        mPauseIconImageView.setVisibility(View.VISIBLE);
                        mTrimVideoView.pause();
                        mTrimVideoView.seekTo(mTrimBarRightTime);
                        mTrimBar.updatePlayTick(mTrimBarRightTime);
                    }
                }

                if (mS3dVideo.isS3dVideo()) {
                    if (mS3dVideo.isS3dMode()) {
                        mS3dIconImageView.setImageResource(R.drawable.icon_3d);
                    } else {
                        mS3dIconImageView.setImageResource(R.drawable.icon_2d);
                    }
                    mS3dIconImageView.setVisibility(View.VISIBLE);
                } else {
                    mS3dIconImageView.setVisibility(View.GONE);
                }
            }
        }, 200);
    }
}
